package com.hushan.audio;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ByteUtil;
import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.avcodec.AVCodec;
import org.bytedeco.ffmpeg.avcodec.AVCodecContext;
import org.bytedeco.ffmpeg.avcodec.AVCodecParameters;
import org.bytedeco.ffmpeg.avcodec.AVPacket;
import org.bytedeco.ffmpeg.avformat.AVFormatContext;
import org.bytedeco.ffmpeg.avformat.AVInputFormat;
import org.bytedeco.ffmpeg.avformat.AVOutputFormat;
import org.bytedeco.ffmpeg.avformat.AVStream;
import org.bytedeco.ffmpeg.avutil.AVChannelLayout;
import org.bytedeco.ffmpeg.avutil.AVDictionary;
import org.bytedeco.ffmpeg.avutil.AVFrame;
import org.bytedeco.ffmpeg.avutil.AVRational;
import org.bytedeco.ffmpeg.swresample.SwrContext;
import org.bytedeco.ffmpeg.global.avformat;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacpp.*;
import org.jboss.resteasy.util.DateUtil;

import javax.sound.sampled.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.ByteOrder;
import java.util.Set;

import static org.bytedeco.ffmpeg.global.avcodec.*;
import static org.bytedeco.ffmpeg.global.avcodec.avcodec_open2;
import static org.bytedeco.ffmpeg.global.avcodec.avcodec_parameters_to_context;
import static org.bytedeco.ffmpeg.global.avdevice.avdevice_register_all;
import static org.bytedeco.ffmpeg.global.avformat.*;
import static org.bytedeco.ffmpeg.global.avutil.*;
import static org.bytedeco.ffmpeg.global.avutil.av_dict_set;
import static org.bytedeco.ffmpeg.global.swresample.*;

@Path("/hello")
@RegisterForReflection(targets = {org.bytedeco.ffmpeg.global.postproc.class})
@Slf4j
public class ExampleResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("file")
    public String hello() {

        Loader.load(avutil.class);
        Loader.load(org.bytedeco.ffmpeg.global.swresample.class);
        Loader.load(org.bytedeco.ffmpeg.global.avcodec.class);
        Loader.load(avformat.class);
        Loader.load(org.bytedeco.ffmpeg.global.swscale.class);
        av_log_set_level(AV_LOG_INFO);
        // Register all formats and codecs
        av_jni_set_java_vm(Loader.getJavaVM(), null);
        avformat_network_init();

        Loader.load(org.bytedeco.ffmpeg.global.avdevice.class);
        avdevice_register_all();


        AVFormatContext inputFormatContext = new AVFormatContext(null);
        AVDictionary options = new AVDictionary(null);
        // 添加网络重试相关选项
        av_dict_set(options, "reconnect", "1", 0); // 启用自动重连
        av_dict_set(options, "reconnect_streamed", "1", 0); // 对流式媒体启用重连
        av_dict_set(options, "reconnect_delay_max", "30", 0); // 最大重连延迟 30 秒
        av_dict_set(options, "timeout", "10000000", 0); // 超时时间设为 10 秒（10000000 微秒）
        AVPacket avPacket = new AVPacket().retainReference();//av_packet_alloc()
        // Open video file
        AVInputFormat inputAvFormat = null;
        AVStream inputAvStream = null;
        long duration;
        int frameSize;
        int targetSampleRate;

        String filename = "C:\\Users\\Administrator\\Music\\就让这大雨全都落下-容祖儿.mp3";
        // 打开输入文件流
        if ((avformat_open_input(inputFormatContext, filename, inputAvFormat, options)) < 0) {
            av_dict_set(options, "pixel_format", null, 0);
            if ((avformat_open_input(inputFormatContext, filename, inputAvFormat, options)) < 0) {
                log.error("avformat_open_input error: Could not open source file {}", filename);
                throw new RuntimeException("获取音频文件超时：" + filename);
            }
        }
        // 确保获取流信息
        if (avformat_find_stream_info(inputFormatContext, (AVDictionary) null) < 0) {
            log.error("avformat_find_stream_info error: Could not find stream information");
            avformat_close_input(inputFormatContext);
            throw new RuntimeException("目标文件中没有音频流");
        }

        av_dump_format(inputFormatContext, 0, filename, 0);

        // Find the first stream with the user-specified disposition property
        int nbStreams = inputFormatContext.nb_streams();
        int audioDisposition = 0;
        int audioStream = -1;
        for (int i = 0; i < nbStreams; i++) {
            AVStream st = inputFormatContext.streams(i);
            AVCodecParameters par = st.codecpar();
            if (audioStream < 0 && par.codec_type() == AVMEDIA_TYPE_AUDIO && st.disposition() == audioDisposition) {
                audioStream = i;
                inputAvStream = st;
            }
        }
        AVCodecParameters audioPar = inputAvStream.codecpar();
        int codecId = audioPar.codec_id();
        AVCodec avCodec = avcodec_find_decoder(codecId);
        AVCodecContext avCodecContext = avcodec_alloc_context3(avCodec);
        avcodec_parameters_to_context(avCodecContext, audioPar);
        if (avcodec_open2(avCodecContext, avCodec, options) < 0) {
            log.error("Could not open codec");
            throw new RuntimeException("Could not open codec");
        }
        long streamDuration = inputAvStream.duration();
        if (streamDuration != avutil.AV_NOPTS_VALUE && streamDuration > 0) {
            AVRational timeBase = inputAvStream.time_base();
            duration = (long) (streamDuration * av_q2d(timeBase));
        } else {
            duration = 0;
        }
        targetSampleRate = audioPar.sample_rate();
        frameSize = avCodecContext.frame_size();

        System.out.println("Duration: " + duration + " seconds" + " Sample Rate: " + targetSampleRate + " Hz Frame Size: " + frameSize);

        while (true) {
            // 读取音频数据包
            int ret = av_read_frame(inputFormatContext, avPacket);
            if (ret >= 0) {
                BytePointer dataPointer = avPacket.data();
                int size = avPacket.size();
                byte[] packetData = new byte[size];
                dataPointer.get(packetData);
                dataPointer.releaseReference();
                av_packet_unref(avPacket);
                // 音频数据回调
                System.out.println("音频数据包大小: " + packetData.length);
                FileUtil.writeBytes(packetData, new File("test.mp3"), 0, packetData.length, true);
            } else {
                break;
            }
        }


        return "Hello from Quarkus REST";
    }
}
